#ifndef GESTURECLASSIFIER_HPP
#define GESTURECLASSIFIER_HPP

/*
 *  GeometricGestureClassifier.hpp
 *  
 *
 *  Created by Rasmus Kyng on 15/01/2011.
 *  Copyright 2011 __MyCompanyName__. All rights reserved.
 *
 */

#include <cv.h>
#include <ml.h>
#include "abstractProbabilityTransformer.hpp"
#include <string>

class GeometricGestureClassifier {
public:
	GeometricGestureClassifier( cv::Ptr< AbstractProbabilityTransformer > probTransPtr );
	
	
	virtual bool classify( cv::Mat& handImg ); //DEPRECATED
	virtual bool segment( cv::Mat& handImg, cv::Rect& forbiddenRect );
	virtual bool segment( cv::Mat& handImg );
	
	virtual bool isHandActive( cv::Mat& handImg );
	
	virtual void updateHist( const cv::Mat& image, const cv::Mat& mask );
	
	virtual double getRelativeConvexityDefect();
	virtual double getContourArea();
	virtual double getConvexHullArea();
	virtual cv::Mat& getContourImage();
	
protected:
	cv::Ptr< AbstractProbabilityTransformer > m_ProbTransPtr;
	
	GeometricGestureClassifier(); //FOR USE BY DERIVATE CLASSSES ONLY
	//NOTE: Is used in HystersisGestureClassifier, which does not need a probTrans.
	//TODO: Refactor this hiearchy so that there is an AbstractGestureClassifier which is a pure virtual class (interface)
	//and derive HysteresisGestureClassifier from that. Also use the AbstractGestureClassifier in general where possible in place of GeometricGestureClassifier.
	
	double m_ConvexHullArea;
	double m_ContourArea;
	double m_RelativeConvexityDefect;

	cv::Mat m_Contour;
	
private:
	void getThresholdedBackProj( cv::Mat& handImg, cv::Mat& bpThreshed );
	bool drawBPContours( cv::Mat& bpThreshed );
};

class MLGestureClassifier : public GeometricGestureClassifier {
public:
	MLGestureClassifier( string pcaName, cv::Ptr< AbstractProbabilityTransformer > probTransPtr );
	
	virtual bool classify( cv::Mat& handImg );
	virtual bool isHandActive( cv::Mat& handImg );
	
	static const cv::Size perSampleSize;
protected:
	cv::PCA pca;
	
	MLGestureClassifier( cv::Ptr< AbstractProbabilityTransformer > probTransPtr ); //ONLY TO BE USED BY DERIVATIVE CLASSES FOR TRAINING
	cv::Mat getResizedImg( cv::Mat& handImg );
	
	virtual bool predict( cv::Mat& dataSampleForPrediction )=0;
private:
};

class SVMGestureClassifier : public MLGestureClassifier {
public:
	SVMGestureClassifier( const char* mlName, string pcaName, cv::Ptr< AbstractProbabilityTransformer > probTransPtr );
protected:
	CvSVM svm;
	virtual bool predict( cv::Mat& dataSampleForPrediction );
private:
};

class BoostGestureClassifier : public MLGestureClassifier {
public:
	BoostGestureClassifier( const char* mlName, string pcaName, cv::Ptr< AbstractProbabilityTransformer > probTransPtr );
	
	//BoostGestureClassifier( string mlAndPcaName, cv::Ptr< AbstractProbabilityTransformer > probTransPtr ); //FOR WHEN NAMES ARE IDENTICAL
	
protected:
	CvBoost boost;
	cv::Mat missingMask; //This is only need due to a bug in OpenCV which does not allow 
	virtual bool predict( cv::Mat& dataSampleForPrediction );
private:
};

class HysteresisGestureClassifier : public GeometricGestureClassifier {
public:
	HysteresisGestureClassifier( cv::Ptr< GeometricGestureClassifier > internalClassifier, int activationThreshold, int deactivationThreshold );
	
	virtual bool classify( cv::Mat& handImg ); //DEPRECATED
	virtual bool segment( cv::Mat& handImg );
	
	virtual bool isHandActive( cv::Mat& handImg );
	
	virtual void updateHist( const cv::Mat& image, const cv::Mat& mask );
	
	virtual double getRelativeConvexityDefect();
	virtual double getContourArea();
	virtual double getConvexHullArea();
	virtual cv::Mat& getContourImage();
protected:
	cv::Ptr< GeometricGestureClassifier > internalClassifier;
	
	int activationThreshold;
	int deactivationThreshold;
	
	int activationCounter;
	int deactivationCounter;
};


#endif